package com.kelp.codetoolkit.service.impl

import ai.grazie.text.find
import com.intellij.database.util.common.isNotNullOrEmpty
import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.guessProjectDir
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.util.registry.EarlyAccessRegistryManager.fileName
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiJavaFile
import com.intellij.psi.PsiManager
import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.psi.xml.XmlFile
import com.intellij.util.containers.stream
import com.kelp.codetoolkit.service.WriteFileService
import com.kelp.codetoolkit.utils.IdeaFileHandleUtil
import com.kelp.codetoolkit.utils.frame.SpringUtil
import java.io.OutputStreamWriter
import java.nio.charset.StandardCharsets
import java.util.stream.Collectors

/**
 * @author: liuyuebai
 * @date: 2024/8/3 13:36
 * @description:
 */
class WriteFileServiceImpl: WriteFileService {

    override fun writeBusinessLogicFile(project: Project, codeParams: MutableMap<String, String>) {
        val projectDir = project.guessProjectDir()
        commonProjectVerify(project,projectDir)
        val fileName = codeParams["fileName"]
        if (fileName.isNullOrBlank()) {
            Messages.showErrorDialog(project,"The file name cannot be empty.","ERROR")
            return
        }
        val codeContent = codeParams["codeContent"]
        if (codeContent.isNullOrBlank()) {
            Messages.showErrorDialog(project,"The $fileName code content is required.","ERROR")
            return
        }
        val businessFilePath = codeParams["businessFilePath"]
        if (businessFilePath.isNullOrBlank()){
            Messages.showErrorDialog(project,"The $fileName package path does not exist.","ERROR")
            return
        }
        var findRelativeFile = VfsUtil.findRelativeFile(businessFilePath, projectDir)
        if (findRelativeFile == null) {
            findRelativeFile = IdeaFileHandleUtil.createDirectory(project, businessFilePath)
        }
        if (null == findRelativeFile) {
            Messages.showErrorDialog(project,"The $fileName creation failed.","ERROR")
            return
        }
        handleCommonWrite(fileName,findRelativeFile,project,codeContent)
    }

    override fun writeImportPackage(project: Project, psiJavaFile: PsiJavaFile, importPsiClassList: MutableSet<PsiClass>) {
        val importList = psiJavaFile.importList ?: return // 如果导入列表为空，则直接返回
        val elementFactory = JavaPsiFacade.getInstance(project).elementFactory
        val existingImports = importList.importStatements.mapNotNull { it.importReference?.qualifiedName }.toSet()
        val newImports = importPsiClassList.filter { it.qualifiedName !in existingImports }
        if (newImports.isEmpty()) return
        // 获取导入列表中的所有导入语句
        WriteCommandAction.runWriteCommandAction(project) {
            newImports.forEach { psiClass ->
                val importStatement = elementFactory.createImportStatement(psiClass)
                importList.add(importStatement)
            }
        }
    }

    override fun writeInterfaceMethod(
        project: Project,
        codeContent: String,
        psiClass: PsiClass
    ) {
        val result = codeContent.trimIndent()
        val factory = JavaPsiFacade.getElementFactory(project)
        val newMethod = factory.createMethodFromText(result, psiClass)
        WriteCommandAction.runWriteCommandAction(project) {
            psiClass.add(newMethod)
        }
    }

    override fun writeXmlContentToFile(
        project: Project,
        xmlVirtualFile: VirtualFile,
        xmlContent:String,
        xmlId: String
    ) {
        val psiFile = PsiManager.getInstance(project).findFile(xmlVirtualFile) as? XmlFile ?: return
        // 所有PSI修改必须在WriteCommandAction中执行
        WriteCommandAction.runWriteCommandAction(project) {
            try {
                val rootTag = psiFile.rootTag ?: return@runWriteCommandAction

                // 创建SQL标签（根据实际类型调整标签名）
                val sqlTag = rootTag.createChildTag(
                    "select",                // 标签名（select/insert/update/delete）
                    rootTag.namespace,       // 继承命名空间
                    xmlContent,              // SQL内容（纯SQL语句，不含标签）
                    false                    // 暂不格式化
                )
                // 关键：添加id和resultType等属性
                sqlTag.setAttribute("id", xmlId)  // 标签唯一标识
                sqlTag.setAttribute("resultType", "")  // 结果类型全类名
                // 添加到<mapper>标签末尾（即</mapper>之前）
                rootTag.addSubTag(sqlTag, false)
                // 格式化代码
                CodeStyleManager.getInstance(project).reformat(rootTag)
            } catch (e: Exception) {
                // 处理异常（如日志记录）
                e.printStackTrace()
            }
        }
    }

    private fun commonProjectVerify(project: Project,projectDir:VirtualFile?){
        if (null == projectDir) {
            Messages.showErrorDialog(project,"The basic project path does not exist.","ERROR")
            throw Exception("The basic project path does not exist.")
        }
    }

    private fun handleCommonWrite(fileName:String,findRelativeFile:VirtualFile,project: Project,codeContent:String){
        val haveExist = findRelativeFile.findChild(fileName)
        if (haveExist != null) {
            Messages.showWarningDialog(project,"The $fileName file already exists.","WARNING")
            return
        }
        val newJavaFile = IdeaFileHandleUtil.run { createFile(project, findRelativeFile, fileName) }
        if (null == newJavaFile) {
            Messages.showErrorDialog(project,"The $fileName creation failed.","ERROR")
            return
        }
        val document = IdeaFileHandleUtil.coverFile(project, newJavaFile, codeContent)
        if (null == document) {
            Messages.showErrorDialog(project,"The $fileName creation failed.","ERROR")
            return
        }
        val psiDocumentManager = PsiDocumentManager.getInstance(project)
        psiDocumentManager.commitDocument(document)
    }
}